The following produces NameError: name 'Client' is not defined
. How can I solve it?
class Server(): def register_client(self, client: Client) pass class Client(): def __init__(self, server: Server): server.register_client(self)
The best solution is to avoid circular dependencies, of course, but it you're truly stuck, you can work around the issue by using property injection and RegisterInstance<T>(T t) (or its equivalent, if you're not using Autofac).
A circular dependency is detected whenever two objects reference each other, in such a way that Power BI cannot process the objects. The details of why this happens are outlined in this article: Understanding Circular Dependencies in Tabular and PowerPivot – SQLBI.
Short version, Callable is a type hint that indicates a function or other object which can be called. Consider a simple example below. The bar parameter is a callable object that takes two ints as parameters and returns an int.
A circular dependency occurs when two or more modules depend on each other. This is due to the fact that each module is defined in terms of the other (See Figure 1). For example: functionA(): functionB() And functionB(): functionA() The code above depicts a fairly obvious circular dependency.
You can use a forward reference by using a string name for the not-yet-defined Client
class:
class Server(): def register_client(self, client: 'Client') pass
As of Python 3.7, you can also postpone all runtime parsing of annotations by adding the following __future__
import at the top of your module:
from __future__ import annotations
at which point the annotations are stored as string representations of the abstract syntax tree for the expression; you can use typing.get_type_hints()
to resolve those (and resolve forward references as used above).
See PEP 563 -- Postponed Evaluation of Annotations for details; this behaviour will be the default in Python 4.0.
If you are on Python 3.7+, use from __future__ import annotations
as mentioned in another answer. However, if you cannot use 3.7 yet due to OS limitation (like Cygwin as of 2019-06-03), you can use Forward References module to satisfy these types of forward/circular dependency issues.
Pardon the contrived example but this should illustrate the usefulness of this methodology.
class Server(): clients: list = None def __init__(self): self.clients=[] def register_client(self, client: 'Client') -> None: self.clients.append(client) print('Client `%s` registered with server' % client.name) def print_clients(self) -> None: for i, client in enumerate(self.clients): print('client %i: %s' % (i, client.name)) @staticmethod def build_clone(server: 'Server') -> 'Server': svr_new: Server = Server() for client in server.clients: svr_new.register_client(client) return svr_new class Client(): name: str = None def __init__(self, name: str, server: 'Server'): self.name = name server.register_client(self) svr = Server() cli = Client('foo', svr) svr.print_clients() svr_clone = Server.build_clone(svr) svr_clone.print_clients()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With