Using Get() with Replacement Functions

Using get() with replacement functions

To understand why this doesn't work, you need to understand what colnames<- does. Like every function in that looks like it's modifying an object, it's actually modifying a copy, so conceptually colnames(x) <- y gets expanded to:

copy <- x
colnames(copy) <- y
x <- copy

which can be written a little more compactly if you call the replacement operator in the usual way:

x <- `colnames<-`(x, y)

So your example becomes

get("x") <- `colnames<-`(get("x"), y)

The right side is valid R, but the command as a whole is not, because you can't assign something to the result of a function:

x <- 1
get("x") <- 2
# Error in get("x") <- 2 :
# target of assignment expands to non-language object

Replacement functions in R that don't take input

After further information from the OP, it looks as if what is needed is a way to write to the existing variable in the environment that calls the function. This can be done with non-standard evaluation:

check_result <- function(process_list) 
{
# Capture the name of the passed object as a string
list_name <- deparse(substitute(process_list))

# Check the object exists in the calling environment
if(!exists(list_name, envir = parent.frame()))
stop("Object '", list_name, "' not found")

# Create a local copy of the passed object in function scope
copy_of_process_list <- get(list_name, envir = parent.frame())

# If the process has completed, write its output to the copy
# and assign the copy to the name of the object in the calling frame
if(length(copy_of_process_list$process$get_exit_status()) > 0)
{
copy_of_process_list$output <- copy_of_process_list$process$read_all_output_lines()
assign(list_name, copy_of_process_list, envir = parent.frame())
}
print(copy_of_process_list)
}

This will update res if the process has completed; otherwise it leaves it alone. In either case it prints out the current contents. If this is client-facing code you will want further type-checking logic on the object passed in.

So I can do

res <- run_sh(c("naw.sh", "hello"))

and check the contents of res I have:

res
#> $`process`
#> PROCESS 'sh', running, pid 1112.
#>
#> $orig_args
#> [1] "naw.sh" "hello"
#>
#> $output
#> NULL

and if I immediately run:

check_result(res)
#> $`process`
#> PROCESS 'sh', running, pid 1112.
#>
#> $orig_args
#> [1] "naw.sh" "hello"
#>
#> $output
#> NULL

we can see that the process hasn't completed yet. However, if I wait a few seconds and call check_result again, I get:

check_result(res)
#> $`process`
#> PROCESS 'sh', finished.
#>
#> $orig_args
#> [1] "naw.sh" "hello"
#>
#> $output
#> [1] "hello" "naw 1" "naw 2" "naw 3" "naw 4" "naw 5"
#> [7] "All done."

and without explicitly writing to res, it has updated via the function:

res
#> $`process`
#> PROCESS 'sh', finished.
#>
#> $orig_args
#> [1] "naw.sh" "hello"
#>
#> $output
#> [1] "hello" "naw 1" "naw 2" "naw 3" "naw 4" "naw 5"
#> [7] "All done."

What are Replacement Functions in R?

When you call

cutoff(x) <- 65

you are in effect calling

x <- "cutoff<-"(x = x, value = 65)

The name of the function has to be quoted as it is a syntactically valid but non-standard name and the parser would interpret <- as the operator not as part of the function name if it weren't quoted.

"cutoff<-"() is just like any other function (albeit with a weird name); it makes a change to its input argument on the basis of value (in this case it is setting any value in x greater than 65 to Inf (infinite)).

The magic is really being done when you call the function like this

cutoff(x) <- 65

because R is parsing that and pulling out the various bits to make the real call shown above.

More generically we have

FUN(obj) <- value

R finds function "FUN<-"() and sets up the call by passing obj and value into "FUN<-"() and arranges for the result of "FUN<-"() to be assigned back to obj, hence it calls:

obj <- "FUN<-"(obj, value)

A useful reference for this information is the R Language Definition Section 3.4.4: Subset assignment ; the discussion is a bit oblique, but seems to be the most official reference there is (replacement functions are mentioned in passing in the R FAQ (differences between R and S-PLUS), and in the R language reference (various technical issues), but I haven't found any further discussion in official documentation).

Python: replacing a function within a class of a module

I suggest 4 solutions, from the worst to the best (IMHO), but of course it also depends on your specific constraints:

  1. Replace the instance method (1): I use the fact that functions are descriptors in Python, so that I can use the __get__ method on AlternativeFunc to get it as a method of the instance mytest and overwrite the testFunc method of the instance mytest (without overwriting the class method):

    class testMOD(object):
    def testFunc(self, variable):
    var = variable
    self.something = var + 12
    print('Original:', self.something)

    def alternativeFunc1(self, variable):
    var = variable
    self.something = var + 1.2
    print('Alternative1:', self.something)

    mytest1 = testMOD()
    mytest1.testFunc(10) # Original: 22

    mytest1.testFunc = alternativeFunc1.__get__(mytest1, testMOD)
    mytest1.testFunc(10) # Alternative1: 11.2
    mytestX = testMOD()
    mytestX.testFunc(10) # Original: 22
  2. Replace the instance method (2): This time, I use types.MethodType which is a bit more readable than the first solution:

    import types

    class testMOD(object):
    def testFunc(self, variable):
    var = variable
    self.something = var + 12
    print('Original:', self.something)

    def alternativeFunc1(self, variable):
    var = variable
    self.something = var + 1.2
    print('Alternative1:', self.something)

    mytest1 = testMOD()
    mytest1.testFunc(10) # Original: 22

    funcType = types.MethodType
    mytest1.testFunc = funcType(alternativeFunc1, mytest1)
    mytest1.testFunc(10) # Alternative1: 11.2
    mytestX = testMOD()
    mytestX.testFunc(10) # Original: 22
  3. Perform a monkey patching of the class method. Differently from the first method, it changes the behavior of any instance of the class:

    class testMOD(object):
    def testFunc(self, variable):
    var = variable
    self.something = var + 12
    print('Original:', self.something)

    def alternativeFunc2(self, variable):
    var = variable
    self.something = var + 1.2
    print('Alternative2:', self.something)

    mytest2 = testMOD()
    mytest2.testFunc(10) # Original: 22

    testMOD.testFunc = alternativeFunc2
    mytest2.testFunc(10) # Alternative2: 11.2
    mytestX = testMOD()
    mytestX.testFunc(10) # Alternative2: 11.2
  4. Create a class inherited from testMOD to override the method:

    class testMODNew(testMOD):
    def testFunc(self, variable):
    var = variable
    self.something = var + 1.2
    print('Alternative3:', self.something)

    mytest3 = testMODNew()
    mytest3.testFunc(10) # Alternative3: 11.2

Replacing words inside the string with that of dictionary without using any kind of replace function

you're there. I'd suggest if instead of listing all characters in the sentence you can split() it with # delimiter, the solution becomes a lot simpler.

'$'.join([toReplace[k] if k in toReplace.keys() else k for k in string.split('#')])
# 'Hi. My name is $xyz$. I am from $abc$. My company is $ttl$.'
  • string.split('#') will generate a list of strings, broken at every '#'
  • The list comprehension will search for the list's strings in the dict's keys, and if found, it will pull the item from the dictionary
  • The resulting list after the comprehension can then be joined using the '#' delimiter as it was split. You could also update the join string to be '$'.

How to use different function to replace an item in list?

The problem here is simple;

You are calling renamer wrongly.

It should be self.renamer() not renamer(self);

Another thing here is your renamer will not work as you are not updating the list.

Here is the complete solution;

files = ["cheese.png","grapes.png","blueberries.png"]


class Ding:

def __init__(self):
files = ["cheese.png","grapes.png","blueberries.png"]
self._filenames = files
self._newFilename = "BLUEBERRIES.PNG"
self._blueberries = self._filenames[2]

def renamer(self):
return [file.upper() if file == self._blueberries else file for file in self._filenames]

def printmessage(self):
print(self.renamer())

Ding().printmessage()

You should now understand how class methods work. We need to access them as self.method_name() as they are not independent functions but class methods.

How to use replace() function in Python for this situation?

slice string and replace only on the slice that interests you, rebuild string.

>>> s = "Land grade 4 year 3 4 members at building 4"
>>> s[0:20]+s[20:24].replace("4","3.5")+s[24:]
'Land grade 4 year 3 3.5 members at building 4'

maybe slightly better with only 1 replacement, which avoids a string slice:

>>> s[0:20]+s[20:].replace("4","3.5",1)
'Land grade 4 year 3 3.5 members at building 4'

But if you know exactly where the number to be replaced is, maybe that's because you could just do that with a template string.

s = "Land grade 4 year 3 {} members at building 4"
s.format(3.5)

Replacement functions in R

There was a change in how R 3.5 stores values in the form a:b. If you try the same example with

library(pryr)
x <- c(1,2,3,4,5,6,7,8,9,10)
address(x)
x[2] <- 7L
address(x)

You should get the same address. Now the 1:10 isn't full expanded until it has to be. And changing an element inside the vector will cause it to expand.

Postgres replace function with an array of values

A natural approach to this type of tasks is to use a loop inside a custom function:

create or replace function multireplace_loop
(string text, pattern text[], replacement text[])
returns text language plpgsql immutable as $$
declare
rec record;
begin
for rec in
select ord, old_str, new_str
from unnest(pattern, replacement)
with ordinality as o(old_str, new_str, ord)
order by ord
loop
string:= replace(string, rec.old_str, rec.new_str);
end loop;
return string;
end $$;

select multireplace_loop
('a string to be replaced', '{string, replaced}', '{cat, dog}');

There is an elegant pure SQL alternative solution applying recursive query:

create or replace function multireplace_recursive
(string text, pattern text[], replacement text[])
returns text language sql immutable as $$
with recursive input_rows as (
select ord, old_str, new_str
from unnest(pattern, replacement)
with ordinality as o(old_str, new_str, ord)
),
recursive_replace as (
select ord, replace(string, old_str, new_str) as string
from input_rows
where ord = 1
union all
select i.ord, replace(string, i.old_str, i.new_str)
from recursive_replace r
join input_rows i on i.ord = r.ord+ 1
)
select string
from recursive_replace
order by ord desc
limit 1
$$;

select multireplace_recursive
('a string to be replaced', '{string, replaced}', '{cat, dog}');

Test it in Db<>Fiddle.



Related Topics



Leave a reply



Submit