# Activity basics - Python SDK

> This section explains Activity Basics with the Python SDK

## Develop a basic Activity 

**How to develop a basic Activity using the Temporal Python SDK.**

One of the primary things that Workflows do is orchestrate the execution of Activities. An Activity is a normal function
or method execution that's intended to execute a single, well-defined action (either short or long-running), such as
querying a database, calling a third-party API, or transcoding a media file. An Activity can interact with the world outside
the Temporal Platform or use a Temporal Client to interact with a Temporal Service. For the Workflow to be able to
execute the Activity, we must define the [Activity Definition](/activity-definition).

You can develop an Activity Definition by using the `@activity.defn` decorator. Register the function as an Activity
with a custom name through a decorator argument, for example `@activity.defn(name="your_activity")`.

> **📝 Note:**
>
> The Temporal Python SDK supports multiple ways of implementing an Activity:
>
> - Asynchronously using [`asyncio`](https://docs.python.org/3/library/asyncio.html)
> - Synchronously multithreaded using
>   [`concurrent.futures.ThreadPoolExecutor`](https://docs.python.org/3/library/concurrent.futures.html#threadpoolexecutor)
> - Synchronously multiprocess using
>   [`concurrent.futures.ProcessPoolExecutor`](https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor)
>   and
>   [`multiprocessing.managers.SyncManager`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.managers.SyncManager)
>
> Blocking the async event loop in Python would turn your asynchronous program into a synchronous program that executes
> serially, defeating the entire purpose of using `asyncio`. This can also lead to potential deadlock, and unpredictable
> behavior that causes tasks to be unable to execute. Debugging these issues can be difficult and time consuming, as
> locating the source of the blocking call might not always be immediately obvious.
>
> Due to this, consider not making blocking calls from within an asynchronous Activity, or use an async safe library to
> perform these actions. If you must use a blocking library, consider using a synchronous Activity instead.
>

<div className="copycode-notice-container">
  <a href="https://github.com/temporalio/documentation/blob/main/sample-apps/python/your_app/your_activities_dacx.py">
    View the source code
  </a>{' '}
  in the context of the rest of the application code.
</div>

```python
from temporalio import activity
# ...
# ...
@activity.defn(name="your_activity")
async def your_activity(input: YourParams) -> str:
    return f"{input.greeting}, {input.name}!"
```

### Develop Activity Parameters 

**How to develop Activity Parameters using the Temporal Python SDK.**

There is no explicit limit to the total number of parameters that an [Activity Definition](/activity-definition) may
support. However, there is a limit to the total size of the data that ends up encoded into a gRPC message Payload.

A single argument is limited to a maximum size of 2 MB. And the total size of a gRPC message, which includes all the
arguments, is limited to a maximum of 4 MB.

Also, keep in mind that all Payload data is recorded in the
[Workflow Execution Event History](/workflow-execution/event#event-history) and large Event Histories can affect Worker
performance. This is because the entire Event History could be transferred to a Worker Process with a
[Workflow Task](/tasks#workflow-task).

Some SDKs require that you pass context objects, others do not. When it comes to your application data—that is, data
that is serialized and encoded into a Payload—we recommend that you use a single object as an argument that wraps the
application data passed to Activities. This is so that you can change what data is passed to the Activity without
breaking a function or method signature.

Activity parameters are the function parameters of the function decorated with `@activity.defn`. These can be any data
type Temporal can convert, including dataclasses when properly type-annotated. Technically this can be multiple
parameters, but Temporal strongly encourages a single dataclass parameter containing all input fields.

<div className="copycode-notice-container">
  <a href="https://github.com/temporalio/documentation/blob/main/sample-apps/python/your_app/your_activities_dacx.py">
    View the source code
  </a>{' '}
  in the context of the rest of the application code.
</div>

```python
from temporalio import activity
from your_dataobject_dacx import YourParams

# ...
# ...
@activity.defn(name="your_activity")
async def your_activity(input: YourParams) -> str:
    return f"{input.greeting}, {input.name}!"
```

### Define Activity return values 

**How to define Activity return values using the Temporal Python SDK.**

All data returned from an Activity must be serializable.

Activity return values are subject to payload size limits in Temporal. The default payload size limit is 2MB, and there
is a hard limit of 4MB for any gRPC message size in the Event History transaction
([see Cloud limits here](https://docs.temporal.io/cloud/limits#per-message-grpc-limit)). Keep in mind that all return
values are recorded in a [Workflow Execution Event History](/workflow-execution/event#event-history).

An Activity Execution can return inputs and other Activity values.

The following example defines an Activity that takes an object as input and returns a string.

<div className="copycode-notice-container">
  <a href="https://github.com/temporalio/documentation/blob/main/sample-apps/python/your_app/your_activities_dacx.py">
    View the source code
  </a>{' '}
  in the context of the rest of the application code.
</div>

```python
# ...
@activity.defn(name="your_activity")
async def your_activity(input: YourParams) -> str:
    return f"{input.greeting}, {input.name}!"
```

### Customize your Activity Type 

**How to customize your Activity Type**

Activities have a Type that are referred to as the Activity name. The following examples demonstrate how to set a custom
name for your Activity Type.

You can customize the Activity name with a custom name in the decorator argument. For example,
`@activity.defn(name="your-activity")`. If the name parameter is not specified, the Activity name defaults to the
function name.

<div className="copycode-notice-container">
  <a href="https://github.com/temporalio/documentation/blob/main/sample-apps/python/your_app/your_activities_dacx.py">
    View the source code
  </a>{' '}
  in the context of the rest of the application code.
</div>

```python
# ...
@activity.defn(name="your_activity")
async def your_activity(input: YourParams) -> str:
    return f"{input.greeting}, {input.name}!"
```
